
#include "stdafx.h"
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include <iostream>
#include "3rdParty/SDL2/include/SDL.h"
#include "Base/Csdl2.h"
#include "Base/Color.h"
#include "Rasterizer.h"
#include "Math/Random.h"


// Learn Include
#include "RTXCode/hittablelist.h"
#include "RTXCode/sphere.h"
#include "RTXCode/camera.h"
#include "RTXCode/material.h"
#include "RTXCode/svpng.inc"

//#include "SDL_test_common.h"
camera cam;
void handleKeyEvent(SDL_Keycode keyCode)
{
	int a = 20;
	switch (keyCode)
	{
	case SDLK_ESCAPE:
		SDL_Quit();
		/* Exit program. */
		exit(0);
		break;
	case SDLK_SPACE:
		break;
	case SDLK_F1:
		//toggle_fullscreen();
		break;
	case SDLK_w:
		cam.camera_move(emMoveUp);
		break;
	case SDLK_s:
		cam.camera_move(emMoveDown);
		break;
	case SDLK_a:
		cam.camera_move(emMoveLeft);
		break;
	case SDLK_d:
		cam.camera_move(emMoveRight);
		break;
	default:
		break;
	}
}

void handleEvents()
{
	// Our SDL event placeholder.  
	SDL_Event event;
	//Grab all the events off the queue.  
	while (SDL_PollEvent(&event)) {
		switch (event.type) {
		case SDL_KEYDOWN:
			// Handle key Event  
			handleKeyEvent(event.key.keysym.sym);
			break;
		case SDL_QUIT:
			// Handle quit requests (like Ctrl-c).  
			SDL_Quit();
			/* Exit program. */
			exit(0);
			break;
		}
	}
}

vec3 color(const ray& r, hittable* world, int depth)
{
	hit_record record;
	if (world->hit(r, 0.0, INT32_MAX, record))
	{
		ray scattered;
		vec3 attenuation;
		if (depth < 50 && record.mat_ptr->scatter(r, record, attenuation, scattered))
		{
			return attenuation * color(scattered, world, depth + 1);
		}
		else
		{
			return vec3(0, 0, 0);
		}
	}
	vec3 vec3UnitDirection = unit_vector(r.direction());
	float t = 0.5 * (1 + vec3UnitDirection.y());
	return (1.0 - t) * vec3(1.0, 1.0, 1.0) + t * vec3(0.5, 0.7, 1.0);
}


#define RUNMODE_REALTIME
#define REALTIME_OFFLINE_PREVIEW
#define PERFRAME_PIXELS 100

#define WIDTH	400
#define HEIGHT	200

int main(int argc, char* args[])
{
	int nx = WIDTH;
	int ny = HEIGHT;
	int ns = 200;

	RenderContext renderContext;
	renderContext.width = nx;
	renderContext.height = ny;
	renderContext.bpp = sizeof(uint32);
	renderContext.backBuffer = new uint32[renderContext.width * renderContext.height];
	renderContext.depthBuffer = new float[renderContext.width * renderContext.height];

	Rasterizer rasterizer(&renderContext);
	Color tmpColor = Color::black;
	CSDL2 *sdl = new CSDL2(nx, ny, "Soft Renderer");
	sdl->Clean(&renderContext, Color::black);


	hittable* list[4];
	list[0] = new sphere(vec3(0, 0, -1), 0.5, new lambertian(vec3(0.8,0.3,0.3)));
	list[1] = new sphere(vec3(0, -100.5, -1), 100, new lambertian(vec3(0.8, 0.8, 0.0)));
	list[2] = new sphere(vec3(1, 0, -1), 0.3, new metal(vec3(0.8, 0.6, 0.2), 0.4));
	list[3] = new sphere(vec3(-1, 0, -1), 0.3, new metal(vec3(0.8, 0.8, 0.8), 0.2));
	hittable* world = new hittable_list(list, 4);

#ifdef REALTIME_OFFLINE_PREVIEW
	int nCurI = 0;
	int nCurJ = 0;
#endif // REALTIME_OFFLINE_PREVIEW

#ifdef RUNMODE_REALTIME
	while (true)
	{
#ifdef REALTIME_OFFLINE_PREVIEW
		for (int i = 0; i < PERFRAME_PIXELS; ++i)
		{
			if (nCurJ >= ny)
				break;
			
			float u = float(nCurI) / float(nx);
			float v = float(nCurJ) / float(ny);

			vec3 col(0, 0, 0);
			for (int s = 0; s < ns; s++)
			{
				float u = float(nCurI + Random::Value()) / float(nx);
				float v = float(nCurJ + Random::Value()) / float(ny);
				ray r = cam.get_ray(u, v);
				col += color(r, world, 0);
			}

			col /= float(ns);
			col = vec3(sqrt(col[0]), sqrt(col[1]), sqrt(col[2]));
			rasterizer.DrawPixel(nCurI, ny - nCurJ - 1, col);

			if (nCurI < nx)
			{
				nCurI++;
			}
			else
			{
				nCurI = 0;
				nCurJ++;
			}
		}
#else
		handleEvents();
		sdl->Clean(&renderContext, Color::white);
		for (int j = 0; j < ny; ++j)
		{
			for (int i = 0; i < nx; ++i)
			{
				float u = float(i) / (float)nx;
				float v = float(j) / (float)ny;

				ray r = cam.get_ray(u, v);
				vec3 col = color(r, world, 0);
				rasterizer.DrawPixel(i, ny - j - 1, col);
			}
		}
#endif
		sdl->SwapBuffer(&renderContext);
	}
#else
	unsigned char rgb[WIDTH * HEIGHT * 3], * p = rgb;
	unsigned x, y;
	FILE* fp = fopen("rgb.png", "wb");

	auto DrawPixel = [&](vec3 col)
	{
		*p++ = col[0] * 255;
		*p++ = col[1] * 255;
		*p++ = col[2] * 255;
	};

	for (int j = ny - 1; j >= 0; --j)
	{
		for (int i = 0; i < nx; ++i)
		{
			vec3 col(0, 0, 0);

			for (int s = 0; s < ns; s++) 
			{
				float u = float(i + Random::Value()) / float(nx);
				float v = float(j + Random::Value()) / float(ny);
				ray r = cam.get_ray(u, v);
				col += color(r, world, 0);
			}

			col /= float(ns);
			col = vec3(sqrt(col[0]), sqrt(col[1]), sqrt(col[2]));

			DrawPixel(col);
		}
	}

	svpng(fp, WIDTH, HEIGHT, rgb, 0);
	fclose(fp);
#endif

	delete[] renderContext.backBuffer;
	delete[] renderContext.depthBuffer;

	getchar();
	return 0;
}